package com.xuesinuo.ots.tool;

import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.xuesinuo.ots.config.auth.Auth;
import com.xuesinuo.ots.config.auth.AuthI18n;
import com.xuesinuo.ots.config.i18n.I18nTips;
import com.xuesinuo.ots.config.spring.ApiCode;
import com.xuesinuo.ots.config.spring.ApiException;
import com.xuesinuo.ots.entity.Role;
import com.xuesinuo.ots.entity.User;
import com.xuesinuo.ots.entity.UserToken;
import com.xuesinuo.ots.util.JsonUtil;
import com.xuesinuo.pignoo.core.Pignoo;

import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 后台（backend）用户工具
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class UserTool {
    private final HttpServletRequest request;
    private final RequestMappingHandlerMapping requestMappingHandlerMapping;
    private final Pignoo pignoo;

    @PostConstruct
    public void init() {
        List<String> i18nAuthList = AuthI18n.authI18ns.stream().map(i18n -> i18n.getAuth()).toList();
        List<String> authList = this.getAllAuth();
        List<String> unI18nAuthList = authList.stream().filter(auth -> !i18nAuthList.contains(auth)).toList();
        List<String> unuseAuthList = i18nAuthList.stream().filter(i18n -> !authList.contains(i18n)).toList();
        log.info("Auth @ " + com.xuesinuo.ots.config.auth.AuthI18n.class);
        boolean errorAuth = false;
        if (unI18nAuthList.size() > 0) {
            log.error("权限未翻译i18n：{}", unI18nAuthList);
            errorAuth = true;
        }
        if (unuseAuthList.size() > 0) {
            log.error("多余的权限i18n：{}", unuseAuthList);
            errorAuth = true;
        }
        if (!errorAuth) {
            log.info("权限配置正常");
        }
    }

    /**
     * 获取权限的多语言名称
     */
    public List<AuthI18n> getAllI18nAuth() {
        List<AuthI18n> result = AuthI18n.authI18ns;
        List<String> set = AuthI18n.authI18ns.stream().map(i18n -> i18n.getAuth()).toList();
        result.addAll(this.getAllAuth().stream()
                .filter(auth -> !set.contains(auth)).map(auth -> new AuthI18n(auth, auth, auth)).toList());
        return result;
    }

    /**
     * 全部权限（摘自@RestController方法头部的@Auth）
     */
    public List<String> getAllAuth() {
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
        List<String> auths = handlerMethods.values().stream().map(handlerMethod -> {
            Auth auth = handlerMethod.getMethodAnnotation(Auth.class);
            if (auth == null || auth.value().trim().equals("")) {
                return null;
            }
            return auth.value();
        }).filter(authString -> authString != null).distinct().sorted().toList();
        return auths;
    }

    /**
     * 验证权限，并获取登录人。（不包含密码）
     */
    public User checkAuth(String auth) {
        User user = this.checkLogin();
        if (user.getAdmin()) {
            return user;
        }
        Role role = pignoo.reader(Role.class).filter(Role::getId, "==", user.getRoleId()).getAny();
        List<String> authList = JsonUtil.toList(role.getAuthJson(), String.class);
        if (!authList.contains(auth)) {
            throw new ApiException(ApiCode.no_auth, I18nTips.no_auth);
        }
        return user;
    }

    /**
     * 验证登录，并获取登录人。（不包含密码）
     */
    public User checkLogin() {
        User user = this.getUser();
        if (user == null) {
            throw new ApiException(ApiCode.not_login, I18nTips.login_first);
        }
        return user;
    }

    /**
     * 查询当前登录人（不包含密码）
     */
    public User getUser() {
        Long userId = this.getUserId();
        if (userId == null) {
            return null;
        }
        User user = pignoo.reader(User.class).filter(User::getId, "==", userId).getAny();
        user.setPassword(null);
        return user;
    }

    /**
     * 查询当前登录
     */
    public Long getUserId() {
        String token = request.getHeader("Token");
        if (token == null) {
            return null;
        }
        UserToken userToken = pignoo.reader(UserToken.class).filter(UserToken::getToken, "==", token).getAny();
        if (userToken == null || userToken.getExpireDatetime() < System.currentTimeMillis()) {
            return null;
        }
        userToken.setExpireDatetime(System.currentTimeMillis() + 2 * 24 * 60 * 60 * 1000);
        return userToken.getUserId();
    }

    /**
     * 登录令牌
     */
    public String getToken() {
        return request.getHeader("Token");
    }
}
